msg_tool\scripts\softpal\img\pgd/
pgd3.rs1use super::base::*;
2use crate::ext::io::*;
3use crate::scripts::base::*;
4use crate::types::*;
5use crate::utils::img::*;
6use crate::utils::struct_pack::*;
7use anyhow::Result;
8use std::io::{Read, Seek};
9
10#[derive(Debug)]
11pub struct Pgd3Builder {}
12
13impl Pgd3Builder {
14 pub fn new() -> Self {
15 Self {}
16 }
17}
18
19impl ScriptBuilder for Pgd3Builder {
20 fn default_encoding(&self) -> Encoding {
21 Encoding::Cp932
22 }
23
24 fn build_script(
25 &self,
26 buf: Vec<u8>,
27 filename: &str,
28 encoding: Encoding,
29 _archive_encoding: Encoding,
30 config: &ExtraConfig,
31 archive: Option<&Box<dyn Script>>,
32 ) -> Result<Box<dyn Script>> {
33 Ok(Box::new(Pgd3::new(
34 MemReader::new(buf),
35 filename,
36 encoding,
37 config,
38 archive,
39 )?))
40 }
41
42 fn extensions(&self) -> &'static [&'static str] {
43 &["pgd"]
44 }
45
46 fn script_type(&self) -> &'static ScriptType {
47 &ScriptType::SoftpalPgd3
48 }
49
50 fn is_image(&self) -> bool {
51 true
52 }
53
54 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
55 if buf_len >= 4 && (buf.starts_with(b"PGD3") || buf.starts_with(b"PGD2")) {
56 return Some(20);
57 }
58 None
59 }
60}
61
62#[derive(Debug)]
63pub struct Pgd3 {
64 header: PgdDiffHeader,
65 base_header: PgdGeHeader,
66 base: ImageData,
67 diff: ImageData,
68}
69
70impl Pgd3 {
71 pub fn new<R: Read + Seek>(
72 mut reader: R,
73 filename: &str,
74 encoding: Encoding,
75 _config: &ExtraConfig,
76 archive: Option<&Box<dyn Script>>,
77 ) -> Result<Self> {
78 let mut sig = [0u8; 4];
79 reader.read_exact(&mut sig)?;
80 if &sig != b"PGD3" && &sig != b"PGD2" {
81 return Err(anyhow::anyhow!("Not a valid PGD3/PGD2 file"));
82 }
83 let header = PgdDiffHeader::unpack(&mut reader, false, encoding)?;
84 let diff = PgdReader::with_diff_header(reader, &header)?.unpack_overlay()?;
85 let base: Vec<u8> = if let Some(archive) = archive {
86 let mut file = archive.open_file_by_name(&header.base_name, true)?;
87 file.data()?
88 } else {
89 let path = {
90 let mut pb = std::path::PathBuf::from(filename);
91 pb.set_file_name(&header.base_name);
92 pb
93 };
94 crate::utils::files::read_file(&path).map_err(|e| {
95 anyhow::anyhow!("Failed to read base image file '{}': {}", path.display(), e)
96 })?
97 };
98 let mut reader = MemReader::new(base);
99 reader.read_exact(&mut sig)?;
100 if &sig != b"GE \0" {
101 return Err(anyhow::anyhow!(
102 "Base image file '{}' is not a valid GE file",
103 header.base_name
104 ));
105 }
106 let base_header = PgdGeHeader::unpack(&mut reader, false, encoding)?;
107 let base = PgdReader::with_ge_header(reader, &base_header)?.unpack_ge()?;
108 Ok(Self {
109 header,
110 base_header,
111 base,
112 diff,
113 })
114 }
115}
116
117impl Script for Pgd3 {
118 fn default_output_script_type(&self) -> OutputScriptType {
119 OutputScriptType::Json
120 }
121
122 fn default_format_type(&self) -> FormatOptions {
123 FormatOptions::None
124 }
125
126 fn is_image(&self) -> bool {
127 true
128 }
129
130 fn export_image(&self) -> Result<ImageData> {
131 let mut base = if self.base_header.is_base_file() {
132 self.base.clone()
133 } else {
134 draw_on_canvas(
135 self.base.clone(),
136 self.base_header.canvas_width,
137 self.base_header.canvas_height,
138 self.base_header.offset_x,
139 self.base_header.offset_y,
140 )?
141 };
142 draw_on_img(
143 &mut base,
144 &self.diff,
145 self.header.offset_x as u32,
146 self.header.offset_y as u32,
147 )?;
148 Ok(base)
149 }
150}
151
152fn draw_on_img(base: &mut ImageData, diff: &ImageData, left: u32, top: u32) -> Result<()> {
153 if base.color_type != diff.color_type {
154 return Err(anyhow::anyhow!(
155 "Color types do not match: {:?} vs {:?}",
156 base.color_type,
157 diff.color_type
158 ));
159 }
160 let bpp = base.color_type.bpp(1) as usize;
161 let base_stride = base.width as usize * bpp;
162 let diff_stride = diff.width as usize * bpp;
163
164 for y in 0..diff.height {
165 let base_y = top + y;
166 if base_y >= base.height {
167 continue; }
169
170 for x in 0..diff.width {
171 let base_x = left + x;
172 if base_x >= base.width {
173 continue; }
175
176 let base_index = (base_y as usize * base_stride) + (base_x as usize * bpp);
177 let diff_index = (y as usize * diff_stride) + (x as usize * bpp);
178
179 let diff_pixel = &diff.data[diff_index..diff_index + bpp];
180 let base_pixel_orig = base.data[base_index..base_index + bpp].to_vec();
181 let mut b = base_pixel_orig[0];
182 let mut g = base_pixel_orig[1];
183 let mut r = base_pixel_orig[2];
184 b ^= diff_pixel[0];
185 g ^= diff_pixel[1];
186 r ^= diff_pixel[2];
187 base.data[base_index] = b;
188 base.data[base_index + 1] = g;
189 base.data[base_index + 2] = r;
190 if bpp == 4 {
191 let mut a = base_pixel_orig[3];
192 a ^= diff_pixel[3];
193 base.data[base_index + 3] = a;
194 }
195 }
196 }
197 Ok(())
198}